package org.xxpay.pay.channel.zypay;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.domain.api.AbstractRes;
import org.xxpay.core.common.domain.api.ApiBuilder;
import org.xxpay.core.common.domain.api.PayRes;
import org.xxpay.core.common.domain.api.msg.QueryRetMsg;
import org.xxpay.core.common.util.AmountUtil;
import org.xxpay.core.common.util.JsonUtil;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.common.util.XXPayUtil;
import org.xxpay.core.common.vo.DBApplicationConfig;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.mq.BaseNotify4MchPay;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.TreeMap;

/**
 * @author: pangxiaoyu
 * @date: 2019年8月21日14:31:57
 */
@Service
public class ZypayPaymentService extends BasePayment {

    @Autowired
    public BaseNotify4MchPay baseNotify4MchPay;

    private static final MyLog _log = MyLog.getLog(ZypayPaymentService.class);

    @Override
    public String getChannelName() {
        return ZypayConfig.CHANNEL_NAME;
    }

    /**
     * 支付
     * @param payOrder
     * @return
     */
    @Override
    public AbstractRes pay(PayOrder payOrder) {
        return doPay(payOrder);
    }

    /**
     * 支付
     * @param payOrder
     * @return
     */
    public AbstractRes doPay(PayOrder payOrder) {
        ZypayConfig zypayConfig = new ZypayConfig(getPayParam(payOrder));
        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);
        DBApplicationConfig dbConfig = getDBApplicationConfig();

        Map<String, Object> paramMap = new TreeMap();
        String pay_applydate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));  //生成提交时间
        String pay_productname = payOrder.getSubject(); // 商品名称
        String pay_amount = AmountUtil.convertCent2Dollar(payOrder.getAmount() + "");
        // 接口类型
        paramMap.put("pay_memberid", zypayConfig.getMchId());                       // 商户ID
        paramMap.put("pay_bankcode", zypayConfig.getBankCode());                    // 银行编码
        paramMap.put("pay_applydate", pay_applydate);                               // 提交时间  时间格式：2016-12-26 18:18:18                                        // 提交时间 时间格式：2016-12-26 18:18:18
        paramMap.put("pay_orderid", payOrder.getPayOrderId());                      // 订单号 上送订单号唯一, 字符长度20
        paramMap.put("pay_notifyurl", super.getNotifyUrl(getChannelName(), dbConfig));    // 服务端通知 服务端返回地址.（POST返回数据）
        paramMap.put("pay_callbackurl", super.getReturnUrl(getChannelName(), dbConfig));  // 页面跳转通知 页面跳转返回地址（POST返回数据）
        paramMap.put("pay_amount", pay_amount);                                     // 订单金额 商品金额
        String mode = zypayConfig.getMode().trim();    // 支付模式
        // 生成签名
        String pay_md5sign = ZypayUtil.getSign(paramMap, zypayConfig.getKey());
        paramMap.put("pay_productname", pay_productname);                           // 商品名称
        paramMap.put("pay_md5sign", pay_md5sign);                           // 签名
        _log.info("{}请求数据:{}, pay_md5sign={}", getChannelName(), paramMap, pay_md5sign);
        String payUrl = zypayConfig.getReqUrl();
        _log.info("{}跳转路径:{}, bankCode:{}, mode:{}", getChannelName(), payUrl, zypayConfig.getBankCode(), zypayConfig.getMode());
        try {
            if ("form".equalsIgnoreCase(mode)) {
                StringBuffer payForm = new StringBuffer();
                payForm.append("<form style=\"display: none\" action=\""+payUrl+"\" method=\"post\">");
                paramMap.keySet().stream().forEach(key ->
                        payForm.append("<input type=\"text\" name=\""+key+"\" value=\""+paramMap.get(key)+"\">")
                );
                payForm.append("<input type=\"submit\" value=\"立即支付\" style=\"display:none\" >");
                payForm.append("</form>");
                payForm.append("<script>document.forms[0].submit();</script>");

                // 存入统一下单地址
                commonService.payOrderService.saveTopayUrl(payOrder.getPayOrderId(), payForm.toString());
                // 返回统一下单跳转地址
                String payJumpUrl =  dbConfig.getPaySiteUrl() + "/api/pay_"+payOrder.getPayOrderId()+".htm";
                retObj.setPayOrderId(payOrder.getPayOrderId());
                retObj.setPayMethod(PayConstant.PAY_METHOD_FORM_JUMP);
                retObj.setJumpInfo(payForm.toString(), payJumpUrl);

            }else if("sdk".equalsIgnoreCase(mode)) {
                String post = ZypayUtil.post(payUrl, paramMap);
                _log.info("[{}]返回结果:{}", getChannelName(), post);
                JSONObject json = JsonUtil.getJSONObjectFromJson(post);
                Boolean status = json.getBoolean("status");
                String topayUrl = json.getString("payurl");
                if(!status) {
                    return ApiBuilder.bizError("调起通道失败[通道下单返回status=false]");
                }

                JSONObject payParamsJSON = new JSONObject();
                payParamsJSON.put("appStr", topayUrl);
                retObj.setAppInfo(PayConstant.PAY_METHOD_ALIPAY_APP, payParamsJSON);

            }else if("url".equalsIgnoreCase(mode)) {
                String post = ZypayUtil.post(payUrl, paramMap);
                _log.info("[{}]返回结果:{}", getChannelName(), post);
                JSONObject json = JsonUtil.getJSONObjectFromJson(post);
                Boolean status = json.getBoolean("status");
                String topayUrl = json.getString("payurl");
                if(!status) {
                    return ApiBuilder.bizError("调起通道失败[通道下单返回status=false]");
                }

                retObj.setJumpInfo(topayUrl);
                StringBuffer payForm = new StringBuffer();
                payForm.append("<script>window.location.href = '"+topayUrl+"';</script>");

                // 存入统一下单地址
                commonService.payOrderService.saveTopayUrl(payOrder.getPayOrderId(), payForm.toString());
                // 返回统一下单跳转地址
                String payJumpUrl =  dbConfig.getPaySiteUrl() + "/api/pay_"+payOrder.getPayOrderId()+".htm";
                retObj.setPayOrderId(payOrder.getPayOrderId());
                retObj.setPayMethod(PayConstant.PAY_METHOD_FORM_JUMP);
                retObj.setJumpInfo(payForm.toString(), payJumpUrl);

            }else if("post".equalsIgnoreCase(mode)) {        // 该种为直接请求，根据返回数据的backtype来处理
                String post = ZypayUtil.post(payUrl, paramMap);
                _log.info("[{}]返回结果:{}", getChannelName(), post);
                JSONObject json = JsonUtil.getJSONObjectFromJson(post);
                String status = json.getString("status");
                if(!"success".equalsIgnoreCase(status)) {
                    return ApiBuilder.bizError("调起通道失败[通道下单返回status="+status+"]");
                }
                String backtype = json.getString("backtype");
                String data = json.getString("data");
                JSONObject payParamsJSON = new JSONObject();
                if("sdk".equalsIgnoreCase(backtype)) {
                    payParamsJSON.put("appStr", data);
                    retObj.setAppInfo(PayConstant.PAY_METHOD_ALIPAY_APP, payParamsJSON);
                }else if("url".equalsIgnoreCase(backtype)) {
                    retObj.setJumpInfo(data);
                    StringBuffer payForm = new StringBuffer();
                    payForm.append("<script>window.location.href = '"+data+"';</script>");

                    // 存入统一下单地址
                    commonService.payOrderService.saveTopayUrl(payOrder.getPayOrderId(), payForm.toString());
                    // 返回统一下单跳转地址
                    String payJumpUrl =  dbConfig.getPaySiteUrl() + "/api/pay_"+payOrder.getPayOrderId()+".htm";
                    retObj.setPayOrderId(payOrder.getPayOrderId());
                    retObj.setPayMethod(PayConstant.PAY_METHOD_FORM_JUMP);
                    retObj.setJumpInfo(payForm.toString(), payJumpUrl);
                }else if("html".equalsIgnoreCase(backtype)) {
                    // 存入统一下单地址
                    commonService.payOrderService.saveTopayUrl(payOrder.getPayOrderId(), data);
                    // 返回统一下单跳转地址
                    String payJumpUrl =  dbConfig.getPaySiteUrl() + "/api/pay_"+payOrder.getPayOrderId()+".htm";
                    retObj.setPayOrderId(payOrder.getPayOrderId());
                    retObj.setPayMethod(PayConstant.PAY_METHOD_FORM_JUMP);
                    retObj.setJumpInfo(data, payJumpUrl);
                }

            }else {
                return ApiBuilder.bizError("调起通道失败[通道配置错误,不存在的mode]");
            }

            int updateCount = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            _log.info("[{}]更新订单状态为支付中:payOrderId={},result={}", getChannelName(), payOrder.getPayOrderId(), updateCount);
            return retObj;
        } catch (Exception e) {
            _log.error(e, "");
            return ApiBuilder.bizError("操作失败!");
        }
    }

    /**
     * 查询订单
     * @param payOrder
     * @return
     */
    @Override
    public QueryRetMsg query(PayOrder payOrder) {
        String logPrefix = "【ZY订单查询】";

        String payOrderId = payOrder.getPayOrderId();
        _log.info("{}开始查询,payOrderId={}", logPrefix, payOrderId);

        ZypayConfig zypayConfig = new ZypayConfig(getPayParam(payOrder));
        JSONObject paramMap = new JSONObject();
        paramMap.put("pay_memberid", zypayConfig.getMchId());
        paramMap.put("pay_orderid", payOrder.getPayOrderId());
        //生成秘钥
        String pay_md5sign = ZypayUtil.getSign(paramMap, zypayConfig.getKey());
        paramMap.put("pay_md5sign", pay_md5sign);

        JSONObject retObj = buildRetObj();
        retObj.put("status", 1);    // 支付中
        String code = "";
        try {
            _log.info("{}请求数据:pay_memberid={}, queryId={}, pay_md5sign={}", logPrefix, zypayConfig.getMchId(), payOrder.getPayOrderId(), pay_md5sign);

            String url = zypayConfig.getReqUrl() + "/Pay_Trade_query.html?";
            String reqData = XXPayUtil.genUrlParams(paramMap);
            String result = XXPayUtil.call4Post(url + reqData);
            _log.info("{}, result={}", logPrefix, ZypayUtil.decodeUnicode(result));

            JSONObject resObj = JSONObject.parseObject(result);
            _log.info("{}返回数据:{}", logPrefix, resObj);

            code = resObj.getString("returncode");
            //状态00为正常
            if ("00".equals(code)){
                String trade_state = resObj.getString("trade_state");
                //SUCCESS为支付成功；NOTPAY为未支付
                if ("SUCCESS".equals(trade_state)){
                    return QueryRetMsg.confirmSuccess(null);  // 成功
                }
                return QueryRetMsg.waiting();  //支付中
            }
        } catch (Exception e) {
            _log.error(e, "");
        }
        return QueryRetMsg.waiting();  //支付中
    }

}
